package com.trade.common.utils;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

/**
 * Class description:对象拷贝通用工具类
 * 该类只能拷贝来源类自己定义的属性到目标类自己定义的属性中，从父类中继承的属性值将不能被拷贝
 *
 * @version V1.0, 2016.03.03 at 11:14:15 CST
 * @JDK Version:  1.8.0_40
 * @Author Shaok Lei
 */
public class BeanUtil {

    /**
     * Method description：拷贝VO对象属性到PO对象属性中，利用反射实现对象之间所有相同属性复制,包括从父级继承的属性
     * Version:V1.0
     * Author:Shaok Lei
     * Date:2016.03.03 at 11:14:44 CST
     *
     * @param source 源对象
     * @param target 目标对象
     * @throws Exception
     */
    public static void copyPropertiesExceptBase(Object source, Object target) throws Exception {
        copySuperExcludeExceptBase(source, target, null);
        copySelfExclude(source, target, null);
    }

    /**
     * Method description：拷贝VO对象属性到PO对象属性中，利用反射实现对象之间相同属性复制，不复制指定名称的属性值，包括继承的属性
     * Version:V1.0
     * Author:Shaok Lei
     * Date:2016.03.03 at 11:15:06 CST
     *
     * @param fromObj      源对象
     * @param toObj        目标对象
     * @param excludsArray 指定不要赋值的对象属性名
     * @throws Exception
     */
    public static void copySuperExcludeExceptBase(Object fromObj, Object toObj, String[] excludsArray) throws Exception {
        List<String> excludesList = null;

        // 判断是否指定了不需要拷贝的属性字段
        if ((excludsArray != null) && (excludsArray.length > 0)) {
            excludesList = Arrays.asList(excludsArray);    // 构造列表对象
        }

        List<Method> toMethodList = new ArrayList<Method>();
        List<Method> fromMethodList = new ArrayList<Method>();

        //如果包含从父级集成的属性字段，过滤掉主键(id)、创建人时间(createTime)、更新时间(modifyTime)、数据状态(dataFlag)、创建人ID()
        if (null == excludesList) {
            excludesList = new ArrayList<String>();
        }
        excludesList.add("id");
        excludesList.add("dataFlag");
        excludesList.add("createTime");
        excludesList.add("createrId");
        excludesList.add("modifyTime");

        // 获取目标对象的父级属性get、set方法列表
        Method[] toMethodSuper = toObj.getClass().getSuperclass().getDeclaredMethods();
        if (toMethodSuper != null) {
            toMethodList = Arrays.asList(toMethodSuper);
        }

        // 获取源对象的父级属性get、set方法列表
        Method[] fromMethodSuper = fromObj.getClass().getSuperclass().getDeclaredMethods();
        if (fromMethodSuper != null) {
            fromMethodList = Arrays.asList(fromMethodSuper);
        }

        Method fromMethod = null;
        Method toMethod = null;
        String fromMethodName = null;
        String toMethodName = null;

        // 循环获取源对象的属性并拷贝
        for (int i = 0; i < fromMethodList.size(); i++) {
            fromMethod = fromMethodList.get(i);
            fromMethodName = fromMethod.getName();

            // 不是get方法的话直接过滤掉
            if (!fromMethodName.contains("get")) {
                continue;
            }

            // 排除列表检测，指定名称的属性值直接过滤掉
            String propertyName = fromMethodName.substring(3, 4).toLowerCase() + fromMethodName.substring(4);
            if ((excludesList != null) && excludesList.contains(propertyName)) {
                continue;
            }

            // 判断在目标对象中是否存在同名属性对应的set方法
            toMethodName = "set" + fromMethodName.substring(3);
            toMethod = findMethodByName(toMethodList, toMethodName);

            if (toMethod == null) {
                continue;
            }

            /*
             * 获取属性值并根据属性值判断属性是否为空，如果不为空则进行赋值操作
             */
            Object value = fromMethod.invoke(fromObj, new Object[0]);

            // 非集合类判空处理
            if (value == null) {
                continue;
            }

            // 集合类判空处理
            if (value instanceof Collection) {
                Collection<?> newValue = (Collection<?>) value;

                if (newValue.size() <= 0) {
                    continue;
                }
            }

            // 通过反射调用set方法进行赋值操作
            Object[] valueObj = new Object[]{value};

            toMethod.invoke(toObj, valueObj);
        }
    }

    /**
     * Method description：拷贝VO对象属性到PO对象属性中，利用反射实现对象之间相同属性复制，不复制指定名称的属性值，不包括继承的属性
     * Version:V1.0
     * Author:Shaok Lei
     * Date:2016.03.03 at 11:15:06 CST
     *
     * @param fromObj      源对象
     * @param toObj        目标对象
     * @param excludsArray 指定不要赋值的对象属性名
     * @throws Exception
     */
    public static void copySelfExclude(Object fromObj, Object toObj, String[] excludsArray) throws Exception {
        List<String> excludesList = null;

        // 判断是否指定了不需要拷贝的属性字段
        if ((excludsArray != null) && (excludsArray.length > 0)) {
            excludesList = Arrays.asList(excludsArray);    // 构造列表对象
        }

        List<Method> toMethodList = new ArrayList<Method>();
        List<Method> fromMethodList = new ArrayList<Method>();

        // 获取目标对象的属性get、set方法列表
        Method[] toMethodSelf = toObj.getClass().getDeclaredMethods();
        if (toMethodSelf != null) {
            toMethodList = Arrays.asList(toMethodSelf);
        }

        // 获取源对象的属性get、set方法列表
        Method[] fromMethodSelf = fromObj.getClass().getDeclaredMethods();
        if (fromMethodSelf != null) {
            fromMethodList = Arrays.asList(fromMethodSelf);
        }

        Method fromMethod = null;
        Method toMethod = null;
        String fromMethodName = null;
        String toMethodName = null;

        // 循环获取源对象的属性并拷贝
        for (int i = 0; i < fromMethodList.size(); i++) {
            fromMethod = fromMethodList.get(i);
            fromMethodName = fromMethod.getName();

            // 不是get方法的话直接过滤掉
            if (!fromMethodName.contains("get")) {
                continue;
            }

            // 排除列表检测，指定名称的属性值直接过滤掉
            String propertyName = fromMethodName.substring(3, 4).toLowerCase() + fromMethodName.substring(4);
            if ((excludesList != null) && excludesList.contains(propertyName)) {
                continue;
            }

            // 判断在目标对象中是否存在同名属性对应的set方法
            toMethodName = "set" + fromMethodName.substring(3);
            toMethod = findMethodByName(toMethodList, toMethodName);

            if (toMethod == null) {
                continue;
            }

            /*
             * 获取属性值并根据属性值判断属性是否为空，如果不为空则进行赋值操作
             */
            Object value = fromMethod.invoke(fromObj, new Object[0]);

            // 非集合类判空处理
            if (value == null) {
                continue;
            }

            // 集合类判空处理
            if (value instanceof Collection) {
                Collection<?> newValue = (Collection<?>) value;

                if (newValue.size() <= 0) {
                    continue;
                }
            }

            // 通过反射调用set方法进行赋值操作
            Object[] valueObj = new Object[]{value};

            toMethod.invoke(toObj, valueObj);
        }
    }

    /**
     * Method description：拷贝VO对象属性到PO对象属性中，利用反射实现对象之间相同属性复制，仅复制指定名称的属性值，只复制从父级继承的属性
     * Version:V1.0
     * Author:Shaok Lei
     * Date:2016.03.03 at 11:15:20 CST
     *
     * @param fromObj      源对象
     * @param toObj        目标对象
     * @param includsArray 指定要赋值的对象属性名
     * @throws Exception
     */
    public static void copySuperInclude(Object fromObj, Object toObj, String[] includsArray) throws Exception {
        List<String> includesList = null;
        // 判断是否指定了需要拷贝的属性字段，如果没有指定则直接结束拷贝
        if ((includsArray != null) && (includsArray.length > 0)) {
            includesList = Arrays.asList(includsArray);
        } else {
            return;
        }

        List<Method> toMethodList = new ArrayList<Method>();
        List<Method> fromMethodList = new ArrayList<Method>();

        //如果包含从父级集成的属性字段，添加更新人ID(modifyId)、描述信息(description)
        if (null == includesList) {
            includesList = new ArrayList<String>();
        }
        includesList.add("modifyId");
        includesList.add("description");

        // 获取目标对象的父级属性get、set方法列表
        Method[] toMethodSuper = toObj.getClass().getSuperclass().getDeclaredMethods();
        if (toMethodSuper != null) {
            toMethodList = Arrays.asList(toMethodSuper);
        }

        // 获取源对象的父级属性get、set方法列表
        Method[] fromMethodSuper = fromObj.getClass().getSuperclass().getDeclaredMethods();
        if (fromMethodSuper != null) {
            fromMethodList = Arrays.asList(fromMethodSuper);
        }

        Method fromMethod = null;
        Method toMethod = null;
        String fromMethodName = null;
        String toMethodName = null;

        // 循环获取源对象的属性并拷贝
        for (int i = 0; i < fromMethodList.size(); i++) {
            fromMethod = fromMethodList.get(i);
            fromMethodName = fromMethod.getName();

            // 不是get方法的话直接过滤掉
            if (!fromMethodName.contains("get")) {
                continue;
            }

            // 包含列表检测
            String propertyName = fromMethodName.substring(3, 1).toLowerCase() + fromMethodName.substring(4);

            if (!includesList.contains(propertyName)) {
                continue;
            }

            // 判断在目标对象中是否存在同名属性对应的set方法
            toMethodName = "set" + fromMethodName.substring(3);
            toMethod = findMethodByName(toMethodList, toMethodName);

            if (toMethod == null) {
                continue;
            }

            /*
             * 获取属性值并根据属性值判断属性是否为空，如果不为空则进行赋值操作
             */
            Object value = fromMethod.invoke(fromObj, new Object[0]);

            // 非集合类判空处理
            if (value == null) {
                continue;
            }

            // 集合类判空处理
            if (value instanceof Collection) {
                Collection<?> newValue = (Collection<?>) value;

                if (newValue.size() <= 0) {
                    continue;
                }
            }

            // 通过反射调用set方法进行赋值操作
            Object[] valueObj = new Object[]{value};

            toMethod.invoke(toObj, valueObj);
        }
    }

    /**
     * Method description：拷贝VO对象属性到PO对象属性中，利用反射实现对象之间相同属性复制，仅复制指定名称的属性值，不包括父级继承的属性
     * Version:V1.0
     * Author:Shaok Lei
     * Date:2016.03.03 at 11:15:20 CST
     *
     * @param fromObj                  源对象
     * @param toObj                    目标对象
     * @param includsArray             指定要赋值的对象属性名
     * @param isIncludeSuperProperties 是否包含充父类集成的属性，true包含，false不包含
     * @throws Exception
     */
    public static void copySelfInclude(Object fromObj, Object toObj, String[] includsArray, boolean isIncludeSuperProperties) throws Exception {
        List<String> includesList = null;
        // 判断是否指定了需要拷贝的属性字段，如果没有指定则直接结束拷贝
        if ((includsArray != null) && (includsArray.length > 0)) {
            includesList = Arrays.asList(includsArray);
        } else {
            return;
        }

        List<Method> toMethodList = new ArrayList<Method>();
        List<Method> fromMethodList = new ArrayList<Method>();

        // 获取目标对象的属性get、set方法列表
        Method[] toMethodSelf = toObj.getClass().getDeclaredMethods();
        if (toMethodSelf != null) {
            toMethodList = Arrays.asList(toMethodSelf);
        }

        // 获取源对象的属性get、set方法列表
        Method[] fromMethodSelf = fromObj.getClass().getDeclaredMethods();
        if (fromMethodSelf != null) {
            fromMethodList = Arrays.asList(fromMethodSelf);
        }


        Method fromMethod = null;
        Method toMethod = null;
        String fromMethodName = null;
        String toMethodName = null;

        // 循环获取源对象的属性并拷贝
        for (int i = 0; i < fromMethodList.size(); i++) {
            fromMethod = fromMethodList.get(i);
            fromMethodName = fromMethod.getName();

            // 不是get方法的话直接过滤掉
            if (!fromMethodName.contains("get")) {
                continue;
            }

            // 包含列表检测
            String propertyName = fromMethodName.substring(3, 1).toLowerCase() + fromMethodName.substring(4);

            if (!includesList.contains(propertyName)) {
                continue;
            }

            // 判断在目标对象中是否存在同名属性对应的set方法
            toMethodName = "set" + fromMethodName.substring(3);
            toMethod = findMethodByName(toMethodList, toMethodName);

            if (toMethod == null) {
                continue;
            }

            /*
             * 获取属性值并根据属性值判断属性是否为空，如果不为空则进行赋值操作
             */
            Object value = fromMethod.invoke(fromObj, new Object[0]);

            // 非集合类判空处理
            if (value == null) {
                continue;
            }

            // 集合类判空处理
            if (value instanceof Collection) {
                Collection<?> newValue = (Collection<?>) value;

                if (newValue.size() <= 0) {
                    continue;
                }
            }

            // 通过反射调用set方法进行赋值操作
            Object[] valueObj = new Object[]{value};

            toMethod.invoke(toObj, valueObj);
        }
    }

    /**
     * Descreption：拷贝PO对象到VO对象中，所有对应的字段都会进行拷贝
     *
     * @param fromObj
     * @param toObj
     * @throws Exception
     * @author：lsk
     */
    public static void copyAllProperties(Object fromObj, Object toObj) throws Exception {
        copyAllSuperProperties(fromObj, toObj);
        copyAllSelfProperties(fromObj, toObj);
    }

    /**
     * 复制所有父级继承的属性
     *
     * @param fromObj
     * @param toObj
     * @throws Exception
     */
    public static void copyAllSuperProperties(Object fromObj, Object toObj) throws Exception {
        List<Method> toMethodList = new ArrayList<Method>();
        List<Method> fromMethodList = new ArrayList<Method>();

        // 获取目标对象的属性get、set方法列表
        Method[] toMethodSuper = toObj.getClass().getSuperclass().getDeclaredMethods();
        if (toMethodSuper != null) {
            toMethodList = Arrays.asList(toMethodSuper);
        }

        // 获取源对象的属性get、set方法列表
        Method[] fromMethodSuper = fromObj.getClass().getSuperclass().getDeclaredMethods();
        if (fromMethodSuper != null) {
            fromMethodList = Arrays.asList(fromMethodSuper);
        }

        Method fromMethod = null;
        Method toMethod = null;
        String fromMethodName = null;
        String toMethodName = null;

        // 循环获取源对象的属性并拷贝
        for (int i = 0; i < fromMethodList.size(); i++) {
            fromMethod = fromMethodList.get(i);
            fromMethodName = fromMethod.getName();

            // 不是get方法的话直接过滤掉
            if (!fromMethodName.contains("get")) {
                continue;
            }

            // 判断在目标对象中是否存在同名属性对应的set方法
            toMethodName = "set" + fromMethodName.substring(3);
            toMethod = findMethodByName(toMethodList, toMethodName);

            if (toMethod == null) {
                continue;
            }

            /*
             * 获取属性值并根据属性值判断属性是否为空，如果不为空则进行赋值操作
             */
            Object value = fromMethod.invoke(fromObj, new Object[0]);

            // 非集合类判空处理
            if (value == null) {
                continue;
            }

            // 集合类判空处理
            if (value instanceof Collection) {
                Collection<?> newValue = (Collection<?>) value;

                if (newValue.size() <= 0) {
                    continue;
                }
            }

            // 通过反射调用set方法进行赋值操作
            Object[] valueObj = new Object[]{value};

            toMethod.invoke(toObj, valueObj);
        }
    }

    /**
     * 赋值所有非父级继承的属性
     *
     * @param fromObj
     * @param toObj
     * @throws Exception
     */
    public static void copyAllSelfProperties(Object fromObj, Object toObj) throws Exception {
        List<Method> toMethodList = new ArrayList<Method>();
        List<Method> fromMethodList = new ArrayList<Method>();

        // 获取目标对象的属性get、set方法列表
        Method[] toMethodSelf = toObj.getClass().getDeclaredMethods();
        if (toMethodSelf != null) {
            toMethodList = Arrays.asList(toMethodSelf);
        }

        // 获取源对象的属性get、set方法列表
        Method[] fromMethodSelf = fromObj.getClass().getDeclaredMethods();
        if (fromMethodSelf != null) {
            fromMethodList = Arrays.asList(fromMethodSelf);
        }

        Method fromMethod = null;
        Method toMethod = null;
        String fromMethodName = null;
        String toMethodName = null;

        // 循环获取源对象的属性并拷贝
        for (int i = 0; i < fromMethodList.size(); i++) {
            fromMethod = fromMethodList.get(i);
            fromMethodName = fromMethod.getName();

            // 不是get方法的话直接过滤掉
            if (!fromMethodName.contains("get")) {
                continue;
            }

            // 判断在目标对象中是否存在同名属性对应的set方法
            toMethodName = "set" + fromMethodName.substring(3);
            toMethod = findMethodByName(toMethodList, toMethodName);

            if (toMethod == null) {
                continue;
            }

            /*
             * 获取属性值并根据属性值判断属性是否为空，如果不为空则进行赋值操作
             */
            Object value = fromMethod.invoke(fromObj, new Object[0]);

            // 非集合类判空处理
            if (value == null) {
                continue;
            }

            // 集合类判空处理
            if (value instanceof Collection) {
                Collection<?> newValue = (Collection<?>) value;

                if (newValue.size() <= 0) {
                    continue;
                }
            }

            // 通过反射调用set方法进行赋值操作
            Object[] valueObj = new Object[]{value};

            toMethod.invoke(toObj, valueObj);
        }
    }

    /**
     * Method description：从方法数组中获取指定名称的方法
     * Version:V1.0
     * Author:Shaok Lei
     * Date:2016.03.03 at 11:15:34 CST
     *
     * @param methods get、set方法集合
     * @param name    方法名称
     * @return
     */
    public static Method findMethodByName(List<Method> methods, String name) {
        for (int j = 0; j < methods.size(); j++) {
            if (methods.get(j).getName().equals(name)) {
                return methods.get(j);
            }
        }

        return null;
    }
}
